import React, {
  FC,
  ReactNode,
  useState,
  useEffect,
  useRef,
  useCallback,
  useMemo,
  memo
} from 'react'
import { Slider } from 'antd'
// import { Link } from 'react-router-dom'
import { useOutsideClick } from '@/hooks'
import PlayerPanel from '../components/app-player-panel'
import { useAppSelector, useAppDispatch, shallowEqualApp } from '@/store'
import {
  changeLyricIndexAction,
  toggleMusicAction,
  changePlayModeAction
} from '../store/player'
import {
  formatTime,
  getImageSize,
  getSongUrl,
  formatSingerName
} from '@/utils/format'
import {
  PlayerBarWrapper,
  BarControl,
  BarPlayerInfo,
  BarOperator,
  BarPlayerLock,
  BarPlayerBlank
} from './style'

interface IProps {
  children?: ReactNode
}

const defaultSingerAvatar = `http://s4.music.126.net/style/web2/img/default/default_album.jpg?param=34y34`

const AppPlayerBar: FC<IProps> = () => {
  const dispatch = useAppDispatch()
  const { currentSong, lyrics, lyricIndex, playMode, playSongList } =
    useAppSelector(
      (state) => ({
        currentSong: state.player.currentSong,
        lyrics: state.player.lyrics,
        lyricIndex: state.player.lyricIndex,
        playMode: state.player.playMode,
        playSongList: state.player.playSongList
      }),
      shallowEqualApp
    )
  // audio实例
  const audioRef = useRef<HTMLAudioElement>(null)
  // slider实例
  const sliderRef = useRef<any>(null)
  // player实例
  const playerContainerRef = useRef<HTMLDivElement>(null)
  // 音乐是否处于播放状态
  const [playing, setPlaying] = useState(false)
  // 音乐总时长
  const [duration, setDuration] = useState(0)
  // 音乐播放进度
  const [progress, setProgress] = useState(0)
  // 音乐当前播放时间
  const [currentTime, setCurrentTime] = useState(0)
  // slider是否处于拖拽状态
  const [sliding, setSliding] = useState(false)
  // 音乐缓冲进度
  const [bufferPercent, setBufferPercent] = useState(0)
  // 控制音量大小
  const [volume, setVolume] = useState(50)
  // 是否锁住播放器
  const [locked, setLocked] = useState(true)
  // 播放列表面板显示/隐藏
  const [panelVisible, setPanelVisible] = useState(false)
  // 音量面板显示/隐藏
  const [volumeVisible, setVolumeVisible] = useState(false)
  // 点击播放进度条
  function handleSliderAfterChange(value: number): void {
    if (playSongList.length === 0) return
    const current = (value / 100) * duration
    audioRef.current!.currentTime = current
    setCurrentTime(current)
    setSliding(false)
  }
  // 拖动播放进度条
  function handleSliderChange(value: number): void {
    const time = (value / 100) * duration
    setCurrentTime(time)
    setProgress(value)
    setSliding(true)
  }
  // 点击音量进度条
  function handleVolumeAfterChange(value: number): void {
    const volumeValue = value / 100
    setVolume(value)
    audioRef.current!.volume = volumeValue
  }
  // 拖动音量进度条
  function handleVolumeChange(value: number): void {
    const volumeValue = value / 100
    setVolume(value)
    audioRef.current!.volume = volumeValue
  }
  // 自动更新进度条
  function handleTimeUpdate(e: any): void {
    const value = (e.target as HTMLAudioElement).currentTime
    if (!sliding) {
      setCurrentTime(value)
      const progressValue = (value / duration) * 100
      setProgress(progressValue)
    }
    // 根据当前播放时间匹配歌词
    let index = lyrics.length - 1
    for (let i = 0; i < lyrics.length; i++) {
      const lyric = lyrics[i]
      if (lyric.time > value * 1000) {
        index = i - 1
        break
      }
    }
    // 确定对应歌词的index
    if (lyricIndex === index || index < 0) return
    dispatch(changeLyricIndexAction(index))
    updateAudioBuffered()
  }
  // 更新音乐缓冲进度
  function updateAudioBuffered(): void {
    const buffered = audioRef.current!.buffered
    if (buffered.length && bufferPercent < 100) {
      const percentValue = (buffered.end(0) / duration) * 100
      setBufferPercent(percentValue)
    }
    sliderRef.current.firstChild.children[2].style.width = bufferPercent + '%'
  }
  // 音乐播放结束
  function handleAudioEnd(): void {
    if (playMode === 2) {
      audioRef.current!.currentTime = 0
      audioRef.current?.play()
    } else {
      handlePlayNextMusic(true)
    }
  }
  // 音乐播放错误
  function handleAudioError(): void {
    setProgress(0)
    setBufferPercent(0)
    setPlaying(false)
  }
  // 音频资源加载完毕时
  function handleCanPlay(): void {
    setPlaying(true)
    audioRef.current!.play().catch(() => {
      setPlaying(false)
    })
  }
  // 播放模式切换
  function handlePlayMode(): void {
    let count = playMode
    const modeCount = ++count % 3
    dispatch(changePlayModeAction(modeCount))
  }
  // 切到下一首歌曲
  function handlePlayNextMusic(isNext = true): void {
    if (playSongList.length) {
      if (playSongList.length === 1 || playMode === 2) {
        audioRef.current!.currentTime = 0
        audioRef.current?.play()
      } else {
        dispatch(toggleMusicAction(isNext))
      }
    }
  }
  // 重置player
  function resetPlayerSlider(): void {
    setProgress(0)
    setBufferPercent(0)
    sliderRef.current.firstChild.children[2].style.width = '0%'
  }
  // 删除播放面板中指定的一首歌曲后的副作用逻辑
  function deleteOneMusic(): void {
    setBufferPercent(0)
    sliderRef.current.firstChild.children[2].style.width = '0%'
  }
  // 修改播放器bottom
  function changePlayerPosition(
    el: any,
    eventName: string,
    eventTag: 'add' | 'remove',
    lockStatus?: boolean,
    start?: number,
    end?: number
  ): void {
    el[`${eventTag}EventListener`](eventName, () => {
      if (eventTag === 'add') {
        if (lockStatus) {
          el.style.bottom = `${start}px`
          return
        }
        el.style.bottom = `${end}px`
      } else {
        return false
      }
    })
  }
  // 控制音乐播放状态
  const togglePlayAudioStatus = useCallback(() => {
    setPlaying(!playing)
    if (playing) {
      audioRef.current!.pause()
    } else {
      audioRef.current!.play().catch(() => {
        setPlaying(false)
      })
    }
  }, [playing])
  // 播放器歌手头像
  const singerAvatar = useMemo(() => {
    if (playSongList.length) {
      return getImageSize(currentSong.al?.picUrl, 34, 34)
    } else {
      return defaultSingerAvatar
    }
  }, [currentSong])
  // 初始化歌曲
  useEffect(() => {
    if (currentSong) {
      const soureUrl = getSongUrl(currentSong.id)
      audioRef.current!.src = soureUrl
      const durationTime = currentSong.dt / 1000
      setDuration(durationTime)
    }
  }, [currentSong])
  // 点击播放器以外区域，音量/播放面板不显示
  useOutsideClick(playerContainerRef.current, () => {
    setPanelVisible(false)
    setVolumeVisible(false)
  })
  // 鼠标移入/移出播放器动画效果
  useEffect(() => {
    const playerDom = playerContainerRef.current
    changePlayerPosition(playerDom, 'mouseleave', 'add', locked, 0, -45)
    changePlayerPosition(playerDom, 'mouseenter', 'add', locked, 0, 0)
    return () => {
      changePlayerPosition(playerDom, 'mouseleave', 'remove')
      changePlayerPosition(playerDom, 'mouseenter', 'remove')
    }
  }, [locked])
  return (
    <PlayerBarWrapper ref={playerContainerRef} className="sprite_playbar">
      <div className="content wrap-v1 sprite_playbar">
        <BarControl playing={playing}>
          <button
            className="btn sprite_playbar prev"
            onClick={() => handlePlayNextMusic(false)}
          ></button>
          <button
            className="btn sprite_playbar pause"
            onClick={() => togglePlayAudioStatus()}
          ></button>
          <button
            className="btn sprite_playbar next"
            onClick={() => handlePlayNextMusic()}
          ></button>
        </BarControl>
        <BarPlayerInfo>
          <a className="default-pic sprite_playbar">
            <img src={singerAvatar} className="image" alt="pic" />
          </a>
          <div className="info">
            <div className="song">
              <span className="song-name">{currentSong?.name}</span>
              <span className="singer-name">
                {formatSingerName(currentSong?.ar)}
              </span>
            </div>
            <div className="progress" ref={sliderRef}>
              <Slider
                value={progress}
                step={0.1}
                tooltip={{ open: false }}
                onChange={handleSliderChange}
                onAfterChange={handleSliderAfterChange}
              />
              <div className="time">
                <span className="current">{formatTime(currentTime)}</span>
                <span className="divider">/</span>
                <span className="duration">{formatTime(duration)}</span>
              </div>
            </div>
          </div>
        </BarPlayerInfo>
        <BarOperator playMode={playMode}>
          <div className="left">
            <button className="btn sprite_playbar favor"></button>
            <button className="btn sprite_playbar share"></button>
            <button className="btn sprite_playbar pip"></button>
          </div>
          <div className="right">
            <div
              className={`${volumeVisible ? 'volume-slider' : 'volume-hide'}`}
            >
              <Slider
                vertical
                value={volume}
                tooltip={{ open: false }}
                onChange={handleVolumeChange}
                onAfterChange={handleVolumeAfterChange}
              />
            </div>
            <button
              className={`
              ${'btn sprite_playbar ' + (volume ? 'volume' : 'novolume')}`}
              onClick={() => setVolumeVisible(!volumeVisible)}
            ></button>
            <button
              className="btn sprite_playbar loop"
              onClick={handlePlayMode}
            ></button>
            <button
              className="btn sprite_playbar playlist"
              onClick={() => setPanelVisible(!panelVisible)}
            ></button>
          </div>
        </BarOperator>
      </div>
      <PlayerPanel
        songList={playSongList}
        panelVisible={panelVisible}
        resetPlaySlider={resetPlayerSlider}
        removeOneMuiscEffect={deleteOneMusic}
        hidePlayerPanel={() => setPanelVisible(false)}
      />
      <BarPlayerLock className="sprite_playbar" locked={locked}>
        <a
          className="lock-btn sprite_playbar"
          onClick={() => setLocked(!locked)}
        ></a>
      </BarPlayerLock>
      <BarPlayerBlank></BarPlayerBlank>
      <audio
        ref={audioRef}
        onCanPlay={handleCanPlay}
        onTimeUpdate={handleTimeUpdate}
        onEnded={handleAudioEnd}
        onError={handleAudioError}
      ></audio>
    </PlayerBarWrapper>
  )
}

export default memo(AppPlayerBar)
